#include "pthreadPool.h"
#define NUM 3

int exitPipe[2];//退出管道
void handler(int signum);//退出信号

/* 线程池 */
int main(int argc, char *argv[])
{
    // ./server 
    ARGS_CHECK(argc,1);

    //父线程管理异步终止
    pipe(exitPipe);
    if(fork()){
        close(exitPipe[0]);
        signal(SIGUSR1,handler);
        wait(NULL);
        printf("Parent is going to exit.\n");
        exit(0);
    }
    close(exitPipe[1]);

    //工人线程池初始化
    int workerNum = NUM;
    threadPool_t threadPool;
    initThreadPool(&threadPool,workerNum);
    makeWorker(&threadPool);

    //网络初始化
    int sockFd = initTcp();
    int epfd = epoll_create(1);
    epollAdd(epfd,sockFd);
    epollAdd(epfd,exitPipe[0]);

    char userName[100] = {0};
    while(1){
        fflush(stdin);
        fflush(stdout);
        printf("Plz enter:\n");
        printf("1: register 2:login\n");

        char buf[10] = {0};
        read(STDIN_FILENO,buf,sizeof(buf));
        if(strcmp(buf,"1")== 0){
            printf("REGISTER\n");
            int ret = registerUser(sockFd);
            if(ret == 1){
                printf("Register failed.\n");
                continue;
            }
            else if (ret == 2){
                printf("UserName exist, register failed.\n");
                continue;
            }
            else{
                printf("Success, Welcome to Cat-Cat-Cat.\n");
                continue;
            }
        }
        else if(strcmp(buf,"2")){
            int ret = login(sockFd,userName);
            if(ret == 2){
                printf("Unregister,bro!\n");
                continue;
            }
            else{
                printf("Oh~ Cat-Cat-Cat.\n");
                break;
            }
        }
        else{
            printf("Wrong num!\n");
            continue;
        }
    }

    epollAdd(epfd,STDIN_FILENO);
    struct epoll_event readySet[2];

    //获取登陆成功的token\key\Dir 用于子线程连接验证
    char token[1024] = {0};
    char key[100] = {0};
    char pwd[1024] = {0};
    int dataLength = 0;

    recvn(sockFd,&dataLength,sizeof(int));
    recvn(sockFd,token,dataLength);
    recvn(sockFd,&dataLength,sizeof(int));
    recvn(sockFd,key,dataLength);
    recvn(sockFd,&dataLength,sizeof(int));
    recvn(sockFd,pwd,dataLength);

    server_t server;
    bzero(&server,sizeof(server));
    strcpy(server.token,token);
    strcpy(server.key,key);
    strcpy(server.userName,userName);

    char cmd[1024] = {0};
    trainState_t trainState;
    bzero(&trainState,sizeof(trainState));
    while(1){
        printf("[%s@ %s:]",userName,pwd);
        fflush(stdin);
        fflush(stdout);
        int readyNum = epoll_wait(epfd,readySet,2,-1);
        for(int i = 0; i < readyNum; ++i){
            if(readySet[i].data.fd == sockFd){
                int check = 0;
                recvn(sockFd,&check,sizeof(check));
                printf("【Master】:It's time to go!\n");

                //发送退出回执
                train_t train;
                bzero(&train,sizeof(train));
                train.length = 0;
                send(sockFd,&train,sizeof(train.length) + train.length,MSG_NOSIGNAL);

                pthread_mutex_lock(&threadPool.mutex);
                threadPool.flag = 1;
                pthread_cond_broadcast(&threadPool.cond);
                pthread_mutex_unlock(&threadPool.mutex);
                for(int j = 0; j < workerNum; ++j){
                    pthread_join(threadPool.tidArr.pthreadTid[j],NULL);
                }
                printf("【Master】: Bye-bye.\n");
                exit(0);
            }
            else if(readySet[i].data.fd == STDIN_FILENO){
                bzero(cmd,sizeof(cmd));
                read(STDIN_FILENO,cmd,sizeof(cmd));
                cmd[strlen(cmd) - 1] = 0;
                printf("cmd = %s\n",cmd);
                bzero(&trainState,sizeof(trainState));

                //命令行处理
                if(strncmp("cd",cmd,2) == 0){
                    if(strlen(cmd) == 2 || cmd[2] != ' '){
                        printf("Cmd wrong!\n");
                        continue;
                    }
                    trainState.state = CD;
                    strcpy(trainState.buf,cmd);
                    trainState.length = strlen(cmd);
                    trainState.preLength = 2;
                    send(sockFd,&trainState,
                         sizeof(trainState.length) + sizeof(trainState.state) + 
                         sizeof(trainState.preLength) + trainState.length,MSG_NOSIGNAL);
                    int check = 0;
                    recvn(sockFd,&check,sizeof(check));
                    if(check != 0){
                        printf("Wong dir name!\n");
                        continue;
                    }
                    recvn(sockFd,&dataLength,sizeof(dataLength));
                    bzero(pwd,sizeof(pwd));
                    recvn(sockFd,pwd,dataLength);
                }
                else if(strncmp("ls",cmd,2) == 0){
                    if(strlen(cmd) == 2 || cmd[2] != ' '){
                        printf("Wrong cmd!\n");
                        continue;
                    }
                    trainState.state = LS;
                    strcpy(trainState.buf,cmd);
                    trainState.length = strlen(cmd);
                    trainState.preLength = 2;
                    send(sockFd,&trainState,
                         sizeof(trainState.length) + sizeof(trainState.state) + 
                         sizeof(trainState.preLength) + trainState.length,MSG_NOSIGNAL);
                    int check = 0;
                    recvn(sockFd,&check,sizeof(check));
                    if(check != 0){
                        printf("Wong dir name!\n");
                        continue;
                    }
                    char fileName[100] = {0};
                    while(1){
                        recvn(sockFd,&dataLength,sizeof(dataLength));
                        if(dataLength == 0){
                            break;
                        }
                        bzero(fileName,sizeof(fileName));
                        recvn(sockFd,fileName,dataLength);
                        printf("%-8s ",fileName);
                    }
                    printf("\n");
                }
                else if(strncmp("pwd",cmd,3) == 0){
                    if(strlen(cmd) > 3){
                        printf("Wrong cmd!\n");
                        continue;
                    }
                    trainState.state = PWD;
                    strcpy(trainState.buf,cmd);
                    trainState.length = strlen(cmd);
                    trainState.preLength = 3;
                    send(sockFd,&trainState,
                         sizeof(trainState.length) + sizeof(trainState.state) + 
                         sizeof(trainState.preLength) + trainState.length,MSG_NOSIGNAL);
                    bzero(pwd,sizeof(pwd));
                    recvn(sockFd,&dataLength,sizeof(dataLength));
                    recvn(sockFd,pwd,dataLength);
                    printf("%s\n",pwd);
                }
                else if(strncmp("rm",cmd,2) == 0){
                    if(strlen(cmd) == 2 || cmd[2] != ' '){
                        printf("Wrong cmd!\n");
                        continue;
                    }
                    trainState.state = REMOVE;
                    strcpy(trainState.buf,cmd);
                    trainState.length = strlen(cmd);
                    trainState.preLength = 2;
                    send(sockFd,&trainState,
                         sizeof(trainState.length) + sizeof(trainState.state) + 
                         sizeof(trainState.preLength) + trainState.length,MSG_NOSIGNAL);
                    int check = 0;
                    recvn(sockFd,&check,sizeof(check));
                    if(check != 0){
                        printf("Wong file name!\n");
                        continue;
                    }
                }
                else if(strncmp("mkdir",cmd,5) == 0){
                    if(strlen(cmd) == 5 || cmd[5] != ' '){
                        printf("Wrong cmd!\n");
                        continue;
                    }
                    trainState.state = MKDIR;
                    strcpy(trainState.buf,cmd);
                    trainState.length = strlen(cmd);
                    trainState.preLength = 5;
                    send(sockFd,&trainState,
                         sizeof(trainState.length) + sizeof(trainState.state) + 
                         sizeof(trainState.preLength) + trainState.length,MSG_NOSIGNAL);
                    int check = 0;
                    recvn(sockFd,&check,sizeof(check));
                    if(check != 0){
                        printf("Can not mkdir!\n");
                        continue;
                    }
                }
                else if(strncmp("puts",cmd,4) == 0){
                    if(strlen(cmd) == 4 || cmd[4] != ' '){
                        printf("Wrong cmd!\n");
                        continue;
                    }
                    trainState.state = PUTS;
                    strcpy(trainState.buf,cmd);
                    trainState.length = strlen(cmd);
                    trainState.preLength = 4;
                    send(sockFd,&trainState,
                         sizeof(trainState.length) + sizeof(trainState.state) + 
                         sizeof(trainState.preLength) + trainState.length,MSG_NOSIGNAL);
                    
                    strcpy(server.cmd,cmd);
                    pthread_mutex_lock(&threadPool.mutex);
                    enQueue(&threadPool.taskQueue,&server);
                    pthread_cond_signal(&threadPool.cond);
                    pthread_mutex_unlock(&threadPool.mutex);
                }
                else if(strncmp("gets",cmd,4) == 0){
                    if(strlen(cmd) == 4 || cmd[4] != ' '){
                        printf("Wrong cmd!\n");
                        continue;
                    }
                    trainState.state = GETS;
                    strcpy(trainState.buf,cmd);
                    trainState.length = strlen(cmd);
                    trainState.preLength = 4;
                    send(sockFd,&trainState,
                         sizeof(trainState.length) + sizeof(trainState.state) + 
                         sizeof(trainState.preLength) + trainState.length,MSG_NOSIGNAL);
                    strcpy(server.cmd,cmd);
                    pthread_mutex_lock(&threadPool.mutex);
                    enQueue(&threadPool.taskQueue,&server);
                    pthread_cond_signal(&threadPool.cond);
                    pthread_mutex_unlock(&threadPool.mutex);
                }
                else{
                    printf("Cmd wrong!\n");
                    continue;
                }
            }
            else{
                train_t train;
                bzero(&train,sizeof(train));
                send(sockFd,&train,sizeof(train.length) + train.length,MSG_NOSIGNAL);

                pthread_mutex_lock(&threadPool.mutex);
                threadPool.flag = 1;
                pthread_cond_broadcast(&threadPool.cond);
                pthread_mutex_unlock(&threadPool.mutex);
                for(int j = 0; j < workerNum; ++j){
                    pthread_join(threadPool.tidArr.pthreadTid[j],NULL);
                }
                printf("【Master】: Bye-bye.\n");
                exit(0);
            }
        }
    }
    close(sockFd);
    return 0;
}

void handler(int signum){
    printf("signum = %d\n",signum);
    write(exitPipe[1],"1",1);
}
